#ifndef __M_ROUTE_H__
#define __M_ROUTE_H__
#include <iostream>
#include "../mqCommon/Helper.hpp"
#include "../mqCommon/proto/mq_message.pb.h"
using std::string;
using std::vector;
using namespace mq_message;

/*  路由交换模块：
    根据交换机类型和匹配规则，对传入的数据进行判断
        1.binding_key合法性判断：可以包含*#
        2.routing_key合法性判断：不可以包含*#，只由数字，字符，. 和 _组成
        3.匹配规则：
            a.直接交换
            b.广播交换
            c.主题交换

    单词：数字，字符，下划线_ 组成
    单词分隔符：.
    通配符：* # 作为单词单独出现，单词内不能同时出现*#，且不能连续出现
    *：表示一个单词
    #：表示零个，一个或多个单词
*/

namespace mq
{
    // 路由交换类
    class Router
    {
    public:
        static bool isLegalRoutingKey(const string &routing_key) // routing_key合法性判断
        {
            for (auto ch : routing_key)
            {
                if ((ch >= 'a' && ch <= 'z') ||
                    (ch >= 'A' && ch <= 'Z') ||
                    (ch >= '1' && ch <= '9') ||
                    (ch == '.' || ch == '_')) // 不可以包含*#，只由数字，字符，. 和 _组成
                    continue;
                return false;
            }
            return true;
        }
        static bool isLegalBindingKey(const string &binging_key) // binding_key合法性判断
        {
            // 1.可以包含 * #
            for (auto ch : binging_key)
            {
                if ((ch >= 'a' && ch <= 'z') ||
                    (ch >= 'A' && ch <= 'Z') ||
                    (ch >= '1' && ch <= '9') ||
                    (ch == '.' || ch <= '_') ||
                    (ch == '#' || ch <= '*'))
                    continue;
                return false;
            }

            vector<string> sub_words;
            StrHelper::split(binging_key, ".", sub_words);
            for (int i = 1; i < sub_words.size(); i++)
            {
                bool flag1 = (sub_words[i].find("*") != string::npos);
                bool flag2 = (sub_words[i].find("#") != string::npos);
                // 2.一个单词同时包含了*#
                if (flag1 && flag2)
                    return false;
                // 3.不是单独出现
                if ((flag1 || flag2) && sub_words[i].size() != 1)
                    return false;
                // 4.*#不能连续出现（**除外）
                if (flag1 && sub_words[i - 1].find("#") != string::npos)
                    return false;
                if (flag2 && (sub_words[i - 1].find("*") != string::npos || sub_words[i - 1].find("#") != string::npos))
                    return false;
            }

            return true;
        }
        /*  匹配规则：binging_key含有*#通配符，routing_key不含通配符
                动规数组：
                1.设bkey单词数为i,rkey单词数为j
                2.定义(i+1)(j+1)二维数组dp
                3.dp[0][0]为1
                4.如果bkey第一个单词为#，则dp[1][0]为1 （例如 #.a 和 a）
                5.其余为0

                动规思想：
                1.当两单词比较，不匹配为0，匹配则继承左上方结果   dp[i][j]=dp[i-1][j-1]
                2.*与单词比较，直接继承左上方结果                dp[i][j]=dp[i-1][j-1]
                3.#与单词比较，继承上方及其左边结果              dp[i][j]=(dp[i-1][j])|(dp[i-1][j-1])|(dp[i-1][j-2])|....
            */
        static bool route(ExchangeType type, const string &routing_key, const string &binging_key) // 根据交换机类型和匹配规则进行路由
        {
            if (!isLegalRoutingKey(routing_key))
            {
                DLOG("routing_key不合法，路由失败： %s", routing_key.c_str());
                return false;
            }
            if (!isLegalBindingKey(binging_key))
            {
                DLOG("binging_key不合法，路由失败： %s", binging_key.c_str());
                return false;
            }

            if (type == DIRECT) // 直接交换
                return routing_key == binging_key;
            else if (type == FANOUT) // 广播交换
                return true;
            else // 主题交换
            {
                // 1.字符串分割
                vector<string> routing_words, binging_words;
                StrHelper::split(routing_key, ".", routing_words);
                StrHelper::split(binging_key, ".", binging_words);
                // 2.定义dp数组，初始化
                int rows = binging_words.size();
                int cols = routing_words.size();
                vector<vector<bool>> dp;
                dp.resize(rows + 1, vector<bool>(cols + 1, false));

                dp[0][0] = true;
                if (binging_words.size() >= 1 && binging_words[0] == "#")
                    dp[1][0] = true;

                // 3.匹配规则
                for (int i = 1; i <= rows; i++)
                {
                    for (int j = 1; j <= cols; j++)
                    {
                        if (binging_words[i - 1] == "#") // #与单词比较，继承上方及其左边结果
                        {
                            for (int k = j; k >= 0; k--)
                            {
                                dp[i][j] = dp[i][j] | dp[i - 1][k];
                            }
                        }
                        else if (binging_words[i - 1] == "*") //*与单词比较，直接继承左上方结果
                        {
                            dp[i][j] = dp[i - 1][j - 1];
                        }
                        else // 当两单词比较，不匹配为0，匹配则继承左上方结果
                        {
                            if (binging_words[i - 1] == routing_words[j - 1])
                                dp[i][j] = dp[i - 1][j - 1];
                        }
                    }
                }
                return dp[rows][cols];
            }
        }
    };
}

#endif